﻿/*************************************************************************************
 * 工 具 名:   HK_FreeCam
 * 
 * 描    述:  漫游摄像机控制脚本，主要用于场景编辑、开发期间，测试观察使用；
 *            运行时可通过鼠标键盘，控制相机移动、旋转、缩放，方便开发及制作人员对场景进行自由观察；
 *            开发测试结束后可直接将该组件移除。
 * 
 * 使用方式：  1.将该脚本添加到Main Camera上，点击运行后即可使用；
 *            2.按住WASD键进行前后左右移动，QE键进行上下移动；
 *            3.按住鼠标右键进行视角旋转；
 *            4.按住Shift进行位移加速；
 *            5.按住鼠标右键，旋转视角
 *            6.滚动鼠标滚轮，视野缩放；
 * 
 * 版    本：  V1.0
 * 创 建 者：  京产肠饭
 * 创建时间：  2021/8/25
 * 链   接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using UnityEngine;

namespace HKTools
{
    public class HK_FreeCam : MonoBehaviour
    {
        [SerializeField, Header("摄像机移动速度：")]
        float moveSpeed = 10;
        float nowMoveSpeed;

        [SerializeField, Header("摄像机旋转速度")]
        float rotateSpeed = 300f;

        [SerializeField, Header("X轴限制范围：")]
        Vector2 xRangeof3D = new Vector3(-45, 45);

        Transform mainCamera_TF;//获取摄像机

        bool isQuicken;

        Vector3 camTargetPos;
        Vector3 camTargetEuler;
        float camFieldOfViewTarget;

        void Start()
        {
            mainCamera_TF = Camera.main.transform;
            camTargetPos = mainCamera_TF.position;
            camTargetEuler = mainCamera_TF.localEulerAngles;
            camFieldOfViewTarget = Camera.main.fieldOfView;
            isQuicken = false;
            nowMoveSpeed = moveSpeed;
        }

        void LateUpdate()
        {
            ControlCam();
            LimitCamXAxisRange(xRangeof3D);
            AddSpeed();
            ZoomCamera();
            LerpCameraPos();
            LerpCameraRot();
        }

        void OnGUI()
        {
            GUIStyle fontStyle = new GUIStyle();
            fontStyle.normal.background = null; //这是设置背景填充的
            fontStyle.normal.textColor = new Color(0.1f, 0.9f, 0); //设置字体颜色的
            fontStyle.fontSize = 20; //当然，这是字体颜色

            GUILayout.Label("1、按住鼠标右键，旋转视角", fontStyle);
            GUILayout.Label("2、滚动鼠标滚轮，缩放视角", fontStyle);
            GUILayout.Label("3、按住W、A、S、D键，前后左右移动", fontStyle);
            GUILayout.Label("4、按住Q、E键，上下移动", fontStyle);
            GUILayout.Label("5、按住Shift键，加速", fontStyle);

            GUILayout.Label("测试结束后，请手动移除该脚本", fontStyle);
        }

        /// <summary>
        /// 3D视角的控制
        /// </summary>
        void ControlCam()
        {
            if (Input.GetKey(KeyCode.W))
                camTargetPos = camTargetPos + mainCamera_TF.forward * nowMoveSpeed * Time.deltaTime;

            if (Input.GetKey(KeyCode.S))
                camTargetPos = camTargetPos - mainCamera_TF.forward * nowMoveSpeed * Time.deltaTime;

            if (Input.GetKey(KeyCode.A))
                camTargetPos = camTargetPos - mainCamera_TF.right * nowMoveSpeed * Time.deltaTime;

            if (Input.GetKey(KeyCode.D))
                camTargetPos = camTargetPos + mainCamera_TF.right * nowMoveSpeed * Time.deltaTime;

            if (Input.GetKey(KeyCode.Q))
                camTargetPos = camTargetPos + Vector3.up * nowMoveSpeed * Time.deltaTime;

            if (Input.GetKey(KeyCode.E))
                camTargetPos = camTargetPos + Vector3.down * nowMoveSpeed * Time.deltaTime;

            if (Input.GetMouseButton(1))
            {
                camTargetEuler = camTargetEuler + Vector3.up * Input.GetAxisRaw("Mouse X") * rotateSpeed * Time.deltaTime;
                camTargetEuler = camTargetEuler + Vector3.left * Input.GetAxisRaw("Mouse Y") * rotateSpeed * Time.deltaTime;
                Cursor.visible = false;
            }

            if (Input.GetMouseButtonUp(1))
                Cursor.visible = true;
        }

        /// <summary>
        /// 限制摄像机俯仰角
        /// </summary>
        /// <param name="xAxis"></param>
        void LimitCamXAxisRange(Vector2 xAxis)
        {
            //当数据突然变到0左右时 会增加到360
            if (camTargetEuler.x > 340)
            {
                camTargetEuler.x = camTargetEuler.x - 360;
                mainCamera_TF.localEulerAngles = camTargetEuler;
            }

            if (camTargetEuler.x > xAxis.y)
                camTargetEuler.x = xAxis.y;

            if (camTargetEuler.x < xAxis.x)
                camTargetEuler.x = xAxis.x;
        }

        /// <summary>
        /// shift 加速
        /// </summary>
        void AddSpeed()
        {
            if (Input.GetKey(KeyCode.LeftShift))
            {
                nowMoveSpeed = moveSpeed * 3;
                isQuicken = true;
            }
            if (Input.GetKeyUp(KeyCode.LeftShift))
            {
                isQuicken = false;
            }

            if (!isQuicken)
            {
                if (nowMoveSpeed > moveSpeed)
                {
                    nowMoveSpeed -= (100 * Time.deltaTime);
                }
                else
                {
                    nowMoveSpeed = moveSpeed;
                }
            }
        }

        /// <summary>
        /// 滚动鼠标中键缩放摄像机
        /// </summary>
        void ZoomCamera()
        {
            //滚动鼠标滑轮缩放摄像机
            if (Input.GetAxis("Mouse ScrollWheel") > 0)
            {
                if (camFieldOfViewTarget >= 40)
                    camFieldOfViewTarget -= 80 * Time.deltaTime;

            }
            if (Input.GetAxis("Mouse ScrollWheel") < 0)
            {
                if (camFieldOfViewTarget <= 80)
                    camFieldOfViewTarget += 80 * Time.deltaTime;
            }

            Camera.main.fieldOfView = Mathf.Lerp(Camera.main.fieldOfView, camFieldOfViewTarget, Time.deltaTime * 10);
        }

        /// <summary>
        /// 摄像机位置 平滑插值
        /// </summary>
        void LerpCameraPos()
        {
            if (Vector3.Distance(mainCamera_TF.position, camTargetPos) > 0.1f)
            {
                mainCamera_TF.position = Vector3.Lerp(mainCamera_TF.position, camTargetPos, Time.deltaTime * 10);
            }
        }

        /// <summary>
        /// 摄像机旋转 平滑插值
        /// </summary>
        void LerpCameraRot()
        {
            if (Quaternion.Dot(mainCamera_TF.rotation, Quaternion.Euler(camTargetEuler)) != 1)
            {
                mainCamera_TF.rotation = Quaternion.Lerp(mainCamera_TF.rotation, Quaternion.Euler(camTargetEuler), Time.deltaTime * 10);
            }
        }
    }
}